﻿using System;
using System.IO;
using System.Linq;
using log4net;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;

namespace YZAutoDWR.Data;

/// <summary>
/// 数据库迁移服务, 表结构变动时自动迁移数据
/// </summary>
public class AutoMigrationService
{
    private readonly DWRDbContext _dbContext;
    private static readonly ILog Log = LogManager.GetLogger(typeof(App));
    private static readonly object MigrationLock = new();
    private const string DbFileName = "UserConfig.db";

    public AutoMigrationService(DWRDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public void RunAutoMigration()
    {
        lock (MigrationLock)
        {
            try
            {
                if (!File.Exists(DbFileName))
                {
                    Log.Info("未检测到数据库文件，将创建新数据库");
                    File.WriteAllBytes(DbFileName, Array.Empty<byte>());
                }

                var pendingMigrations = _dbContext.Database.GetPendingMigrations().ToList();
                if (!pendingMigrations.Any())
                {
                    Log.Info("数据库已是最新版本");
                    return;
                }

                Log.Info($"检测到待应用迁移: {string.Join(", ", pendingMigrations)}");

                var backupPath = CreateBackup();
                try
                {
                    _dbContext.Database.Migrate();
                    Log.Info("数据库迁移成功完成");

                    // 迁移成功后删除过期的备份（保留最近3个）
                    CleanOldBackups(keepLast: 3);
                }
                catch
                {
                    Log.Warn("迁移失败，尝试恢复备份...");
                    RestoreBackup(backupPath);
                    throw;
                }
            }
            catch (Exception ex)
            {
                Log.Error("数据库迁移失败", ex);
                throw new MigrationException("数据库自动迁移失败", ex);
            }
        }
    }

    private static string CreateBackup()
    {
        var backupPath = $"UserConfig_Backup_{DateTime.Now:yyyyMMddHHmmss}.db";
        File.Copy(DbFileName, backupPath);
        Log.Info($"已创建数据库备份: {backupPath}");
        return backupPath;
    }

    private static void RestoreBackup(string backupPath)
    {
        if (File.Exists(backupPath))
        {
            File.Copy(backupPath, DbFileName, overwrite: true);
            Log.Warn($"已从备份恢复数据库: {backupPath}");
        }
        else
        {
            Log.Error("找不到有效的数据库备份文件");
        }
    }

    private static void CleanOldBackups(int keepLast)
    {
        var backups = Directory.GetFiles(Directory.GetCurrentDirectory(), "UserConfig_Backup_*.db")
            .OrderByDescending(f => f)
            .Skip(keepLast)
            .ToList();

        foreach (var backup in backups)
        {
            try
            {
                File.Delete(backup);
                Log.Info($"已清理旧备份: {Path.GetFileName(backup)}");
            }
            catch (Exception ex)
            {
                Log.Warn($"清理备份失败: {backup}", ex);
            }
        }
    }
}

public class MigrationsIdGenerator : IMigrationsIdGenerator
{
    public string GenerateId(string name) => name;
    public string GetName(string id) => id;
    public bool IsValidId(string value) => !string.IsNullOrWhiteSpace(value);
}

public class MigrationException : Exception
{
    public MigrationException(string message, Exception inner)
        : base(message, inner)
    {
    }
}